package models;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.*;

import models.Comment;
import models.Organization;
import models.Tag;
import models.Topic;
import models.User;

import play.data.validation.*;
import play.db.jpa.Model;

@Entity
public class Idea extends Model {
	@OneToMany(mappedBy = "relatedIdea", cascade = CascadeType.ALL)
	public List<Role> roles;
	@Required
	private String title;
	@Required
	private String ideaDetail;
	@Required
	private float rating;
	@Required
	private boolean isDraft;
	@Required
	private boolean activityStatus;
	@Required
	private boolean executionStatus;
	@Required
	@ManyToOne
	private Organization organization;
	@Required
	@ManyToOne
	private Eentity entity;
	@Required
	private boolean hide;
	@Required
	private boolean lock;
	@Required
	private boolean spam;

	@Required
	@ManyToOne
	private Topic topic;

	@Required
	@OneToMany(mappedBy = "idea", cascade = CascadeType.ALL)
	private List<Comment> comments;
	@Required
	@ManyToMany(mappedBy = "taggedIdeas", cascade = CascadeType.ALL)
	private List<Tag> tags;
	@Required
	@ManyToMany(mappedBy = "ideaList", cascade = CascadeType.ALL)
	private List<User> members;

	@Required
	@OneToMany(mappedBy = "idea", cascade = CascadeType.ALL)
	private List<Rating> ratings;
	@Required
	private String averageRating;

	// The plan that may execute the idea Author: Andrew Guirguis
	@Required
	@ManyToOne
	private Plan plan;

	@Required
	private int views;

	// Idea constructor Author: Caroline Tawfik
	// I Changed in The idea Constructor to take LinkedList of User
	// not just a user Author:Aly Mostafa

	public Idea(String title, String ideaDetail, boolean isDraft, Topic t,
			LinkedList<User> creators) {
		this.title = title;
		this.ideaDetail = ideaDetail;
		this.rating = 0;
		this.isDraft = isDraft;
		this.activityStatus = false;
		this.executionStatus = false;

		this.averageRating = "";
		this.comments = new LinkedList<Comment>();
		this.tags = new LinkedList<Tag>();
		// this.members = creators; // possible error 
		this.members = new LinkedList<User>(); //Amr Draz fix
		
		// for merging ideas we have to have a
									// linkedList <User>
		// using setCreators method...caroline
		this.hide = false;
		this.lock = false;
		this.spam = false;
		
		this.setTopic(t);
		this.setCreators(creators);
		System.out.println("creator Set");
		ratings = new LinkedList<Rating>();
		// t.getIdeas().add(this);

		for (int i = 0; i < this.members.size(); i++) {
			if (members.get(i) != null)
				members.get(i).getIdeaList().add(this);
			// members.get(i).save();
		}

		t.addIdea(this);
		this.setViews(0);
	}

	public Idea(String title, String ideaDetail, boolean isDraft,
			Organization org, LinkedList<User> creators) {
		this.title = title;
		this.ideaDetail = ideaDetail;
		this.rating = 0;
		this.isDraft = isDraft;
		this.activityStatus = false;
		this.executionStatus = false;

		this.organization = org;

		this.averageRating = "";
		this.comments = new LinkedList<Comment>();
		this.tags = new LinkedList<Tag>();

		this.hide = false;
		this.lock = false;
		this.spam = false;
		// this.members = creators; // for merging ideas we have to have a // possible error <-- written by Draz
									// linkedList <User>
		this.members = new LinkedList<User>(); //Amr Draz fix 
		
		// creators.add(creator);
		ratings = new LinkedList<Rating>();
		// LinkedList<Idea> temp =new LinkedList();
		// temp.add(this);
		// org.setIdeas(temp);
		this.setCreators(creators);
		for (int i = 0; i < this.members.size(); i++) {

			members.get(i).getIdeaList().add(this);
			// members.get(i).save();
		}
		org.getIdeas().add(this);
		this.setViews(0);

	}

	public Idea(String title, String ideaDetail, boolean isDraft, Eentity ent,
			LinkedList<User> creators) {
		this.title = title;
		this.ideaDetail = ideaDetail;
		this.rating = 0;
		this.isDraft = isDraft;
		this.activityStatus = false;
		this.executionStatus = false;

		this.entity = ent;

		this.averageRating = "";
		this.comments = new LinkedList<Comment>();
		this.tags = new LinkedList<Tag>();

		this.hide = false;
		this.lock = false;
		this.spam = false;
		// this.members = creators; // for merging ideas we have to have a // possible error <-- written by Draz
		// linkedList <User>
		this.members = new LinkedList<User>(); //Amr Draz fix 
		
		// creators.add(creator);
		ratings = new LinkedList<Rating>();

		this.setViews(0);
		System.out.println("setting creators");
		this.setCreators(creators);
		System.out.println("creator set");
		for (int i = 0; i < this.members.size(); i++) {

			members.get(i).getIdeaList().add(this);
			// members.get(i).save();
		}
		ent.getIdeas().add(this);
		this.save();
	}

	// Default constructor for idea Author:Caroline Tawfik
	public Idea() {
		this.title = "";
		this.ideaDetail = "";
		this.rating = 0;
		this.isDraft = false;
		this.activityStatus = false;
		this.executionStatus = false;
		this.organization = null;
		this.topic = null;
		this.comments = new LinkedList<Comment>();
		this.tags = new LinkedList<Tag>();
		this.hide = false;
		this.lock = false;
		this.members = new LinkedList<User>();
		averageRating = "";
		ratings = new LinkedList<Rating>();
		this.setViews(0);
		this.spam = false;

	}

	/**
	 * returns a list of all ideas in the system.
	 * 
	 * @author karim.khalaf
	 * @version 2010.0424
	 * @category C3D1
	 * @return List<Idea>
	 */
	public static List<Idea> returnAllIdeas() {
		List allIdeas = Idea.findAll();
		return allIdeas;
	}

	/**
	 * Adding a Tag to idea.
	 * 
	 * @author Ibrahim Kessba
	 * @version 2010.0424
	 * @category C2D10
	 * @param commingTag
	 *            : Tag to be added to the idea
	 * @return void
	 */
	public void addTag(Tag tag) {
		if (!tags.contains(tag)) {
			tags.add(tag);
			tag.addIdea(this);
		}
	}

	/**
	 * Removing a Tag form idea.
	 * 
	 * @author Ibrahim Kessba
	 * @version 2010.0424
	 * @category C2D10
	 * @param commingTag
	 *            : Tag to be removed from the idea
	 * @return void
	 */
	public void removeTag(Tag commingTag) {
		int index = tags.indexOf(commingTag);
		tags.remove(index);
	}

	/**
	 * returns a list of all ideas in a certain entity (not the ones saved as
	 * draft/hidden/locked).
	 * 
	 * @author wassim.gabriel
	 * @version 2010.0502
	 * @category C3D3
	 * @param requestedEntity
	 * @return List<Idea>
	 */
	public List<Idea> ideasInEntity(long requestedEntity) {
		List<Idea> ideas = Idea.find("byId", "requestedEntity").fetch();
		for (int i = 0; i < ideas.size(); i++) {
			if (ideas.get(i).isDraft() || ideas.get(i).isHide()
					|| ideas.get(i).isLock()) {
				ideas.remove(i);
			}
		}
		return ideas;
	}

	/**
	 * Returns info about idea
	 * 
	 * @author Nader Alexan
	 * @version 2010.0427
	 * @category extra
	 * @return String
	 */

	public String toString() {
		return "Title: " + title + "\nDetails: " + ideaDetail + "\nRating: "
				+ rating + "\nDraft: " + ((isDraft) ? "Yes" : "No")
				+ "\nActivity Status: "
				+ ((activityStatus) ? "Active " : "Inactive ")
				+ "\nExecution Status: "
				+ ((executionStatus) ? "Executed " : "Not Executed ")
				+ "\nOrganization: " + organization + "\nEntity: " + entity
				+ "\nHiden: " + ((hide) ? "Yes " : "No ") + "\nLocked: "
				+ ((lock) ? "Yes" : "No");
	}

	/**
	 * Same as toString except with
	 * <p>
	 * instead of \n
	 * 
	 * @author Nader Alexan
	 * @version 2010.0505
	 * @category extra
	 * @return String
	 */
	public String toStringP() {
		return "Title: " + title + "<p>Details: " + ideaDetail + "<p>Rating: "
				+ rating + "<p>Draft: " + ((isDraft) ? "Yes" : "No")
				+ "<p>Activity Status: "
				+ ((activityStatus) ? "Active " : "Inactive ")
				+ "<p>Execution Status: "
				+ ((executionStatus) ? "Executed " : "Not Executed ")
				+ "<p>Organization: " + organization + "<p>Entity: " + entity
				+ "<p>Hiden: " + ((hide) ? "Yes " : "No ") + "<p>Locked: "
				+ ((lock) ? "Yes" : "No") + "<p>";
	}

	/**
	 * Returns info about the idea in the form of an array
	 * 
	 * @author Nader Alexan
	 * @version 2010.0505
	 * @category extra
	 * @return String []
	 */

	public String[] toArray() {
		String[] result = { "Title:", title, "Details:", ideaDetail,
				"Rating: ", "" + rating, "Draft:", ((isDraft) ? "Yes" : "No"),
				"Activity Status:", ((activityStatus) ? "Active" : "Inactive"),
				"Execution Status:",
				((executionStatus) ? "Executed" : "Not Executed"),
				"Organization: ", "" + organization, "Entity: ", "" + entity,
				"Hiden: ", ((hide) ? "Yes" : "No") + "Locked",
				((lock) ? "Yes" : "No") };
		return result;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getIdeaDetail() {
		return ideaDetail;
	}

	public void setIdeaDetail(String ideaDetail) {
		this.ideaDetail = ideaDetail;
	}

	public float getRating() {
		return rating;
	}

	public void setRating(float rating) {
		this.rating = rating;
	}

	public boolean isDraft() {
		return isDraft;
	}

	public void setDraft(boolean isDraft) {
		this.isDraft = isDraft;
	}

	public boolean isActivityStatus() {
		return activityStatus;
	}

	public void setActivityStatus(boolean activityStatus) {
		this.activityStatus = activityStatus;
	}

	public boolean isExecutionStatus() {
		return executionStatus;
	}

	public void setExecutionStatus(boolean executionStatus) {
		this.executionStatus = executionStatus;
	}

	public Organization getOrganization() {
		return organization;
	}

	public void setOrganization(Organization organization) {
		if (this.organization != organization) {
			this.organization = organization;
			organization.addIdea(this);
		}
	}

	public Eentity getEntity() {
		return entity;
	}

	public void setEntity(Eentity entity) {
		if (this.entity != entity) {
			this.entity = entity;
			setOrganization(entity.getOrganization());
			entity.addIdea(this);
		}
	}

	public Topic getTopic() {
		return topic;
	}

	public void setTopic(Topic topic) {

		this.topic = topic;
		setOrganization(topic.getOrganization());
		topic.addIdea(this);

	}

	public List<Comment> getComments() {
		return comments;
	}

	public void setComments(LinkedList<Comment> comments) {
		this.comments = comments;
	}

	public List getTags() {
		return tags;
	}

	public LinkedList<User> getIdeaFollowers() {
		LinkedList<User> followers = new LinkedList<User>();

		for (int i = 0; i < members.size(); i++) {
			for (int j = 0; j < members.get(i).getRoleList().size(); j++) {
				if (members.get(i).getRoleList().get(j).getTitle()
						.equalsIgnoreCase("Follower")
						&& (members.get(i).getRoleList().get(j)
								.getRelatedIdea() != null)
						&& members.get(i).getRoleList().get(j).getRelatedIdea()
								.equals(this)) {
					followers.add(members.get(i));
				}
			}

		}
		return followers;
	}

	public void setIdeaFollowers(User follower) {
		follower.getRoleList().add(new Role(this, "Follower"));
		members.add(follower);
	}

	public boolean isHide() {
		return hide;
	}

	public void setHide(boolean hide) {
		this.hide = hide;
	}

	public boolean isLock() {
		return lock;
	}

	public void setLock(boolean lock) {
		this.lock = lock;
	}

	public LinkedList<User> getCreators() {
		LinkedList<User> creators = new LinkedList<User>();

		for (int i = 0; i < members.size(); i++) {
			for (int j = 0; j < members.get(i).getRoleList().size(); j++) {
				// System.out.println(members.get(i).getRoleList().get(i).getUser().getfName());
				if (members.get(i).getRoleList().get(j).getTitle()
						.equalsIgnoreCase("Creator")
						&& (members.get(i).getRoleList().get(j)
								.getRelatedIdea() != null)
						&& members.get(i).getRoleList().get(j).getRelatedIdea()
								.equals(this)) {
					members.add(members.get(i));
				}
			}

		}
		return creators;
	}

	public void setCreators(List<User> creators) {
		System.out.println("checking that creators is not null because otherwise I'm to lazy to add them");
		if (creators != null) {
			System.out.println("started adding creators which it's size is " + creators.size());
			for (int i = 0; i < creators.size(); i++) {
				
				if (creators.get(i) == null)
					continue;
				System.out.println("adding creator n."+i+" user:"+creators.get(i).getUsername());
				creators.get(i).getRoleList().add(new Role(this, "Creator"));

				members.add(creators.get(i));
				System.out.println("added creator to members");
				this.save();
				
			}
		}
	}

	public List<Rating> getRatings() {
		return ratings;
	}

	public void setRatings(List<Rating> ratings) {
		this.ratings = ratings;
	}

	public String getAverageRating() {
		return averageRating;
	}

	public void setAverageRating(String averageRating) {
		this.averageRating = averageRating;
	}

	public void setTags(List<Tag> tags) {
		this.tags = tags;
	}

	public void setFollowers(User follower) {
		follower.getRoleList().add(new Role(this, "Follower"));
		members.add(follower);
	}

	/**
	 * Calculates the current average rating of the idea
	 * 
	 * @author Arwa Ismail
	 * @version 2010.0429
	 * @category C4S10
	 * @return void
	 */

	public void calculateAverageRating() {

		float temp = 0; // changed to float

		for (int i = 0; i < ratings.size(); i++) {
			if (ratings.get(i).getRating().equalsIgnoreCase("high"))
				temp = temp + 3;

			if (ratings.get(i).getRating().equalsIgnoreCase("medium"))
				temp = temp + 2;

			if (ratings.get(i).getRating().equalsIgnoreCase("low"))
				temp = temp + 1;
		}

		float temp2 = temp / (ratings.size());

		if (temp2 < 1.65)
			this.averageRating = "Low";
		else {
			if (temp2 < 2.35)
				this.averageRating = "Medium";
			else
				this.averageRating = "High";
		}

	}

	public void setPlan(Plan plan) {
		if (this.plan != plan) {
			this.plan = plan;
		}
	}

	public Plan getPlan() {
		return plan;
	}

	public void setViews(int views) {
		this.views = views;
	}

	public int getViews() {
		return views;
	}

	public List<User> getMembers() {
		return members;
	}

	public void setMembers(List<User> members) {
		this.members = members;
	}

	public void setComments(List<Comment> comments) {
		this.comments = comments;
	}

	public boolean isSpam() {
		return spam;
	}

	public void setSpam(boolean spam) {
		this.spam = spam;
	}

	public void addMember(User user) {
		if (!has(user)) {
			members.add(user);
			user.addIdea(this);
		}
	}

	public void addComment(Comment comment) {
		if (!has(comment)) {
			comments.add(comment);
			comment.setIdea(this);
		}
	}

	private boolean has(Comment comment) {
		for (int i = 0; i < comments.size(); i++)
			if (comments.get(i).id == comment.id)
				return true;
		return false;
	}

	private boolean has(Tag tag) {
		for (int i = 0; i < tags.size(); i++)
			if (tags.get(i).id == tag.id)
				return true;
		return false;
	}

	private boolean has(User user) {
		for (int i = 0; i < members.size(); i++)
			if (members.get(i).id == user.id)
				return true;
		return false;
	}

}
